﻿define([
    'Wjs/ui/widgets/foundation/ViewHashContainer',
    'Wjs/ui/widgets/foundation/ViewSingleContainer',
    'Wjs/ui/widgets/Grid',
    'Wjs/ui/elements/util/Selector',
    'Wjs/ui/widgets/fields/Button',
    'Wjs/ui/elements/Text'
],
function () {
    'use strict';

    var ViewHashContainer = Wjs.getType('ViewHashContainer'),
        getDatePicker,
        DaysInWeek = 7,
        WeeksInMonth = 6;

    return Wjs.defineOnce({

        type: 'DatePicker',

        internal: {

            base: Wjs.getType('Grid'),

            onBeforeTypeDefined: function () {

                getDatePicker = function (item) {

                    return item.up(function (p) {

                        return p instanceof Wjs.getType('Grid');
                    })
                };

                // DatePickerDayCell
                Wjs.define({

                    type: 'DatePickerDayCell',

                    internal: {

                        base: Wjs.getType('GridBodyCell'),

                        initialize: function () {

                            //this.addClass('wjs-display-flex wjs-date-picker-caption-month');
                        }
                    },

                    getDay: function () {

                        return this.day;
                    },

                    enable: function () {

                        this.disabled = false;

                        this.removeClass('wjs-disabled');

                        return this;
                    },

                    disable: function () {

                        this.disabled = true;

                        this.addClass('wjs-disabled');

                        return this;
                    }
                });

                // DatePickerCaptionMonth
                Wjs.define({

                    type: 'DatePickerCaptionMonth',

                    internal: {

                        base: ViewHashContainer,

                        initialize: function () {

                            this.addClass('wjs-display-flex wjs-date-picker-caption-month');

                            this.addSection('previous',

                                Wjs.new('ViewSingleContainer')

                                    .setItem(

                                        Wjs.new('Button')

                                            .setText('<')

                                            .onClick(function (event) {
                                                var datePicker = getDatePicker(this),
                                                    date = datePicker.getPreviousMonthDate();

                                                datePicker.setDate(date);
                                            })
                                    )
                            );

                            this.addSection('month',

                                Wjs.new('ViewSingleContainer')

                                    .addClass('wjs-display-flex-1')

                                    .setText('Month')
                            );

                            this.addSection('next',

                                Wjs.new('ViewSingleContainer')

                                    .setItem(

                                        Wjs.new('Button')

                                            .setText('>')

                                            .onClick(function (event) {
                                                var datePicker = getDatePicker(this),
                                                    date = datePicker.getNextMonthDate();

                                                datePicker.setDate(date);
                                            })
                                    )
                            );
                        }
                    },

                    getPreviousButton: function () {

                        return this.getSection('previous');
                    },

                    getMonth: function () {

                        return this.getSection('month');
                    },

                    getNextButton: function () {

                        return this.getSection('next');
                    }
                });

                // DatePickerCaptionYear
                Wjs.define({

                    type: 'DatePickerCaptionYear',

                    internal: {

                        base: ViewHashContainer,

                        initialize: function () {

                            this.addClass('wjs-display-flex wjs-date-picker-caption-year');

                            this.addSection('previous',

                                Wjs.new('ViewSingleContainer')

                                    .setItem(

                                        Wjs.new('Button')

                                            .setText('<')

                                            .onClick(function (event) {
                                                var datePicker = getDatePicker(this),
                                                    date = datePicker.getPreviousYearDate();

                                                datePicker.setDate(date);
                                            })
                                    )
                            );

                            this.addSection('year',

                                Wjs.new('ViewSingleContainer')

                                    .addClass('wjs-display-flex-1')

                                    .setText('Year')
                            );

                            this.addSection('next',

                                Wjs.new('ViewSingleContainer')

                                    .setItem(

                                        Wjs.new('Button')

                                            .setText('>')

                                            .onClick(function (event) {
                                                var datePicker = getDatePicker(this),
                                                    date = datePicker.getNextYearDate();

                                                datePicker.setDate(date);
                                            })
                                    )
                            );
                        }
                    },

                    getPreviousButton: function () {

                        return this.getSection('previous');
                    },

                    getYear: function () {

                        return this.getSection('year');
                    },

                    getNextButton: function () {

                        return this.getSection('next');
                    }
                });

                // DatePickerCaption
                Wjs.define({

                    type: 'DatePickerCaption',

                    internal: {

                        base: ViewHashContainer,

                        initialize: function () {

                            this.setTag('caption');

                            this.addClass('wjs-display-flex wjs-date-picker-caption');

                            this.addSection('month',

                                Wjs.new('DatePickerCaptionMonth')
                                    .addClass('wjs-display-flex')
                            );

                            this.addSection('year',

                                Wjs.new('DatePickerCaptionYear')
                                    .addClass('wjs-display-flex')
                            );
                        }
                    },

                    getMonthLabel: function () {

                        return this.getSection('month').getMonth();
                    },

                    getMonthPreviousButton: function () {

                        return this.getSection('month').getPreviousButton().getItem();
                    },

                    getMonthNextButton: function () {

                        return this.getSection('month').getNextButton().getItem();
                    },

                    getYearLabel: function () {

                        return this.getSection('year').getYear();
                    },

                    getYearPreviousButton: function () {

                        return this.getSection('year').getPreviousButton().getItem();
                    },

                    getYearNextButton: function () {

                        return this.getSection('year').getNextButton().getItem();
                    },

                });

            },

            initialize: function () {

                this.getBody().onItemAdded(function (row) {
                    row.defaultItemType = 'DatePickerDayCell';
                });

                this.addClass('wjs-date-picker');

                this.setMonthNames(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']);

                this.setWeekDayNames(['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']);

                this.setCellSelector(

                    Wjs.new('Selector')

                        .onBeforeSelect(function (item) {

                            return item.getContent() !== ''; // It the item has a day text then it can be selected
                        })
                );

                this.setCaptionItem(

                    Wjs.new(this.defaultCaptionType)
                );

                this.initColumns();

                this.initCells();
            }

        },

        setMonthNames: function (monthNames) {

            this.monthNames = monthNames;
        },

        setWeekDayNames: function (weekDayNames) {

            this.weekDayNames = weekDayNames;
        },

        onDateSelected: function (fcn) {

            this.dateSelectedHandler = Wjs.chain(this.dateSelectedHandler, fcn);

            return this;
        },

        // Called when the date is set in the date picker (either a different month or year)
        onDateSet: function (fcn) {

            this.dateSetHandler = Wjs.chain(this.dateSetHandler, fcn)

            return this;
        },

        findCellByDay: function (day) {

            return this.getBody().down(function (item) {

                return item instanceof Wjs.getType('DatePickerDayCell') &&
                    item.getDay() == day;
            })[0];

        },

        disableDays: function (days) {

            days.forEach(function (day) {

                this.findCellByDay(day).disable();
            },
            this);
        },

        // Called when the day is set in the day cell
        onDaySet: function (fcn) {

            this.daySetHandler = fcn;

            return this;
        },

        setMinDate: function (date) {

            this.minDate = date;

            return this;
        },

        setMaxDate: function (date) {

            this.maxDate = date;

            return this;
        },

        // Default function to disable the dates
        // before the min data and the previous button when the min date is showing
        // and after the max date and to disable the next button when the max date is showing
        dateSetHandler: function () {
            var captionItem = this.getCaption().getItem();

            if (this.minDate) {

                // If the min date belongs to this year, do not allow the picker to go back any year
                if (this.minDate.getFullYear() == this.year) {

                    captionItem.getYearPreviousButton().disable();
                }
                else {

                    captionItem.getYearPreviousButton().enable();
                }

                // If the min date is on this year and this month then do not allow the date picker to go back any month
                if (this.minDate.getMonth() == this.month &&
                    this.minDate.getFullYear() == this.year) {

                    captionItem.getMonthPreviousButton().disable();

                    // Disable the days before this

                }
                else {

                    captionItem.getMonthPreviousButton().enable();

                }
            }

            if (this.maxDate) {

                // If the min date belongs to this year, do not allow the picker to go back any year
                if (this.maxDate.getFullYear() == this.year) {

                    captionItem.getYearNextButton().disable();
                }
                else {

                    captionItem.getYearNextButton().enable();
                }

                // If the min date is on this year and this month then do not allow the date picker to go back any month
                if (this.maxDate.getMonth() == this.month &&
                    this.maxDate.getFullYear() == this.year) {

                    captionItem.getMonthNextButton().disable();

                    // Disable the days before this

                }
                else {

                    captionItem.getMonthNextButton().enable();

                }
            }
        },

        defaultCaptionType: 'DatePickerCaption',

        initColumns: function () {
            var i,
                length = 7,
                fields = [
                    'sunday',
                    'monday',
                    'tuesday',
                    'wednesday',
                    'thursday',
                    'friday',
                    'saturday'
                ];

            for (i = 0; i < length; ++i) {

                this.addColumn(

                     Wjs.new('GridColumn')

                       .setHeaderText(this.weekDayNames[i])

                       .setField(fields[i])

                       .setWidth(30)
                );
            }

        },

        initCells: function () {
            var i,
                weeks = 6;

            for (i = 0; i < weeks; ++i) {

                this.addRow({
                    sunday: '',
                    monday: '',
                    tuesday: '',
                    wednesday: '',
                    thursday: '',
                    friday: '',
                    saturday: ''
                });
            }
        },

        setDate: function (date) {
            var month,
                year,
                firstDayOfWeek,
                lastDayOfMonth,
                dow,
                row,
                cell,
                counter = 1,
                w,
                captionItem;

            if (!date || !Wjs.isDate(date)) {

                throw 'setDate requires a date as a parameter'
            }

            month = date.getMonth();

            year = date.getFullYear();

            firstDayOfWeek = new Date(year, month, 1).getDay();

            lastDayOfMonth = new Date(year, month + 1, 0).getDate();

            // Create a new grid
            this.getBody().clearItems();

            this.initCells();

            // Set the first week
            row = this.getRow(0);

            for (dow = firstDayOfWeek; dow < DaysInWeek; ++dow) {

                cell = row.getCell(dow);

                cell.day = counter++;

                cell.getItem().setText(cell.day);

                if (this.daySetHandler) {

                    this.daySetHandler(cell, dow);
                }
            }

            // Set the other weeks
            for (w = 1; w < WeeksInMonth && counter <= lastDayOfMonth; ++w) {

                row = this.getRow(w);

                for (dow = 0; dow < DaysInWeek && counter <= lastDayOfMonth; ++dow) {

                    cell = row.getCell(dow);

                    cell.day = counter++;

                    cell.getItem().setText(cell.day);

                    if (this.daySetHandler) {

                        this.daySetHandler(cell, dow);
                    }
                }
            }

            captionItem = this.getCaption().getItem();

            captionItem.getMonthLabel().setText(this.monthNames[month]);

            captionItem.getYearLabel().setText(year);

            this.year = year;

            this.month = month;

            // Select the cell with the day
            this.findCellByDay(date.getDate()).select();

            if (this.dateSetHandler) {

                this.dateSetHandler(date);
            }

            return this;
        },

        selectionChangedHandler: function (cfg) {
            var day;

            if (cfg.selectionType == 'select') {

                day = cfg.currentSelection[0].getContent();

                if (this.dateSelectedHandler) {

                    this.dateSelectedHandler(new Date(this.year, this.month, day));
                }
            }

        },

        // Returns the date that corresponds to the previous month of the current date in the date picker
        getPreviousMonthDate: function () {

            return new Date(this.year, this.month - 1, 1);
        },

        // Returns the date that corresponds to the previous month of the current date in the date picker
        getNextMonthDate: function () {

            return new Date(this.year, this.month + 1, 1);
        },

        // Returns the date that corresponds to the previous month of the current date in the date picker
        getPreviousYearDate: function () {

            return new Date(this.year - 1, this.month, 1);
        },

        // Returns the date that corresponds to the previous month of the current date in the date picker
        getNextYearDate: function () {

            return new Date(this.year + 1, this.month, 1);
        }

    });

});